﻿#ifndef REMOTEOBJECTNODE_H
#define REMOTEOBJECTNODE_H

#include <memory>
#include "workcondition.h"
#include "messagechannel.h"
#include "metainfo.h"
#include "classfactory.h"

class RemoteObject;
class DynamicRemoteObject;

struct RemoteObjectNodeBasePrivate;
struct RemoteObjectNodePrivate;

class RemoteObjectNodeBase:public ThreadSafe::ThreadSafeBase
{
public:
    RemoteObjectNodeBase(RemoteObjectNodeBasePrivate* p);
    virtual ~RemoteObjectNodeBase();
    virtual void close() = 0;
    bool isActive() const;
protected:
    virtual void OnMessage(Message* message);
    void SendMessage(Message* message);
    void SendMessage(Message* message,ClientId id);
    virtual void UnRegister(RemoteObject* obj);
protected:
    std::shared_ptr<RemoteObjectNodeBasePrivate> _P;

private:
    void slotOnMessage();
    friend class RemoteObject;
};

class RemoteObjectData;
class REFLECTX_EXPORT RemoteObjectNode:public RemoteObjectNodeBase
{
private:
    RemoteObjectNode(RemoteObjectNodePrivate* P);
public:
    RemoteObjectNode();
    virtual ~RemoteObjectNode();

    void connectTo(std::string hostName);

	void SetClassFactory(ClassFactory factory);

	//使用给定的ClassFactory和shareName获取远程对象。如果此时host没有该对象，则返回空指针
	RemoteObject* Acquire(std::string shareName);

	//使用给定的类型和shareName获取远程对象。如果此时host没有该对象，则依旧能够返回对象。当host开始共享时，该对象会被自动初始化
    template<typename T>
    T* Acquire(){
        auto meta = T::staticMetaInfo();
        return dynamic_cast<T*>(Acquire(meta.ClassName().c_str(),meta));
    }

	template<typename T>
	T* Acquire(const char* shareName) {
		auto meta = T::staticMetaInfo();
		return dynamic_cast<T*>(Acquire(shareName, meta));
	}
    virtual DynamicRemoteObject* AcquireDynamic(const char* shareName);
	virtual RemoteObject* Acquire(const char* shareName, MetaInfo info);
	void close() override;

public:
	//服务端有新的对象开始共享了
	Signal<std::string, std::string> newObject;

protected:
    void OnMessage(Message* message) override;
    void UnRegister(RemoteObject* obj) override;
    RemoteObjectData* findObject(RemoteObject* obj);

    void pushProperty(RemoteObject* obj,int idx,const Variant& param);
    std::shared_ptr<WorkFuture<Variant>> invokeFunction(RemoteObject* obj,int idx,const VariantList& param,bool sync = false);
private:
	void InputValueFix(Variant& v,MetaTypeId targetId);
	bool OutputValueFix(Variant& v);

private:
    RemoteObjectNodePrivate* _d();
    friend class RemoteObject;
    friend class DynamicRemoteObject;
};

#endif // REMOTEOBJECTNODE_H
